home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / nhclb120.zoo / lapb.c < prev    next >
C/C++ Source or Header  |  1992-06-18  |  15KB  |  634 lines

  1. /* Link Access Procedures Balanced (LAPB) - with changes for rational
  2.  * behavior over packet radio
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "ax25.h"
  8. #include "lapb.h"
  9. #include "iface.h"
  10. #ifdef    UNIX
  11. #include <memory.h>
  12. #endif
  13. static int ackours();
  14. static int procdata();
  15. /* Process incoming frames */
  16. int
  17. lapb_input(axp,cmdrsp,bp)
  18. struct ax25_cb *axp;        /* Link control structure */
  19. char cmdrsp;            /* Command/response flag */
  20. struct mbuf *bp;        /* Rest of frame, starting with ctl */
  21. {
  22.     int16 ftype();
  23.     void lapbstate();
  24.     char control;
  25.     char class;        /* General class (I/S/U) of frame */
  26.     int16 type;        /* Specific type (I/RR/RNR/etc) of frame */
  27.     char pf;        /* extracted poll/final bit */
  28.     char poll = 0;
  29.     char final = 0;
  30.     int nr;            /* ACK number of incoming frame */
  31.     int ns;            /* Seq number of incoming frame */
  32.     char tmp;
  33.  
  34.     if(bp == NULLBUF || axp == NULLAX25){
  35.         free_p(bp);
  36.         return -1;
  37.     }
  38.  
  39.     /* Extract the various parts of the control field for easy use */
  40.     control = pullchar(&bp);
  41.     type = ftype(control);
  42.     class = type & 0x3;
  43.     pf = control & PF;
  44.     /* Check for polls and finals */
  45.     if(pf){
  46.         switch(cmdrsp){
  47.         case COMMAND:
  48.             poll = YES;
  49.             break;
  50.         case RESPONSE:
  51.             final = YES;
  52.             break;
  53.         }
  54.     }
  55.     /* Extract sequence numbers, if present */
  56.     switch(class){
  57.     case I:
  58.     case I+2:
  59.         ns = (control >> 1) & MMASK;
  60.     case S:    /* Note fall-thru */
  61.         nr = (control >> 5) & MMASK;
  62.         break;
  63.     }
  64.     /* This section follows the SDL diagrams by K3NA fairly closely */
  65.     switch(axp->state){
  66.     case DISCONNECTED:
  67.         switch(type){
  68.         case SABM:    /* Initialize or reset link */
  69.             sendctl(axp,RESPONSE,UA|pf);    /* Always accept */
  70.             clr_ex(axp);
  71.             axp->unack = axp->vr = axp->vs = 0;
  72.             lapbstate(axp,CONNECTED);/* Resets state counters */
  73.             start_timer(&axp->t3);
  74.             break;
  75.         case DM:    /* Ignore to avoid infinite loops */
  76.             break;
  77.         default:    /* All others get DM */
  78.             sendctl(axp,RESPONSE,DM|pf);
  79.             break;
  80.         }
  81.         break;
  82.     case SETUP:
  83.         switch(type){
  84.         case SABM:    /* Simultaneous open */
  85.             sendctl(axp,RESPONSE,UA|pf);
  86.             break;
  87.         case DISC:
  88.             sendctl(axp,RESPONSE,DM|pf);
  89.             break;
  90.         case UA:    /* Connection accepted */
  91.             /* Note: xmit queue not cleared */
  92.             stop_timer(&axp->t1);
  93.             start_timer(&axp->t3);
  94.             axp->unack = axp->vr = axp->vs = 0;
  95.             lapbstate(axp,CONNECTED);
  96.             break;            
  97.         case DM:    /* Connection refused */
  98.             free_q(&axp->txq);
  99.             stop_timer(&axp->t1);
  100.             lapbstate(axp,DISCONNECTED);
  101.             break;
  102.         default:    /* All other frames ignored */
  103.             break;
  104.         }
  105.         break;
  106.     case DISCPENDING:
  107.         switch(type){
  108.         case SABM:
  109.             sendctl(axp,RESPONSE,DM|pf);
  110.             break;
  111.         case DISC:
  112.             sendctl(axp,RESPONSE,UA|pf);
  113.             break;
  114.         case UA:
  115.         case DM:
  116.             stop_timer(&axp->t1);
  117.             lapbstate(axp,DISCONNECTED);
  118.             break;
  119.         default:    /* Respond with DM only to command polls */
  120.             if(poll)
  121.                 sendctl(axp,RESPONSE,DM|pf);
  122.             break;
  123.         }
  124.         break;
  125.     case CONNECTED:
  126.         switch(type){
  127.         case SABM:
  128.             sendctl(axp,RESPONSE,UA|pf);
  129.             clr_ex(axp);
  130.             free_q(&axp->txq);
  131.             stop_timer(&axp->t1);
  132.             start_timer(&axp->t3);
  133.             axp->unack = axp->vr = axp->vs = 0;
  134.             lapbstate(axp,CONNECTED); /* Purge queues */
  135.             break;
  136.         case DISC:
  137.             free_q(&axp->txq);
  138.             sendctl(axp,RESPONSE,UA|pf);
  139.             stop_timer(&axp->t1);
  140.             stop_timer(&axp->t3);
  141.             lapbstate(axp,DISCONNECTED);
  142.             break;
  143. /* This code is cribbed from the NOS version, in order to make a */
  144. /* temporary fix to a pathological looping behavior during connect (dmf) */
  145.         case DM:
  146.             lapbstate(axp,DISCONNECTED);
  147.             break;
  148.         case UA:
  149.             est_link(axp);
  150.             lapbstate(axp,SETUP);    /* Re-establish */    
  151.             break;
  152. /* End of cribbed code (dmf) */            
  153.         case FRMR:
  154.             est_link(axp);
  155.             lapbstate(axp,SETUP);    /* Re-establish link */
  156.             break;
  157.         case RR:
  158.         case RNR:
  159.             axp->remotebusy = (control == RNR) ? YES : NO;
  160.             if(poll)
  161.                 enq_resp(axp);
  162.             (void)ackours(axp,nr);
  163.             break;
  164.         case REJ:
  165.             axp->remotebusy = NO;
  166.             if(poll)
  167.                 enq_resp(axp);
  168.             (void)ackours(axp,nr);
  169.             stop_timer(&axp->t1);
  170.             start_timer(&axp->t3);
  171.             /* This may or may not actually invoke transmission,
  172.              * depending on whether this REJ was caused by
  173.              * our losing his prior ACK.
  174.              */
  175.             inv_rex(axp);
  176.             break;    
  177.         case I:
  178.             (void)ackours(axp,nr); /** == -1) */
  179.             if(len_mbuf(axp->rxq) >= axp->window){
  180.                 /* Too bad he didn't listen to us; he'll
  181.                  * have to resend the frame later. This
  182.                  * drastic action is necessary to avoid
  183.                  * deadlock.
  184.                  */
  185.                 if(poll)
  186.                     sendctl(axp,RESPONSE,RNR|pf);
  187.                 free_p(bp);
  188.                 bp = NULLBUF;
  189.                 break;
  190.             }
  191.             /* Reject or ignore I-frames with receive sequence number errors */
  192.             if(ns != axp->vr){
  193.                 if(axp->proto == V1 || !axp->rejsent){
  194.                     axp->rejsent = YES;
  195.                     sendctl(axp,RESPONSE,REJ | pf);
  196.                 }
  197.                 axp->response = 0;
  198.                 stop_timer(&axp->t2);
  199.                 break;
  200.             }
  201.             axp->rejsent = NO;
  202.             axp->vr = (axp->vr+1) & MMASK;
  203.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  204.             if(poll){
  205.                 sendctl(axp,RESPONSE,tmp|PF);
  206.             } else {
  207.                 axp->response = tmp;
  208.                 start_timer(&axp->t2);
  209.             }
  210.             procdata(axp,bp);
  211.             bp = NULLBUF;
  212.             break;
  213.         default:    /* All others ignored */
  214.             break;
  215.         }
  216.         break;
  217.     case RECOVERY:
  218.         switch(type){
  219.         case SABM:
  220.             sendctl(axp,RESPONSE,UA|pf);
  221.             clr_ex(axp);
  222.             stop_timer(&axp->t1);
  223.             start_timer(&axp->t3);
  224.             axp->unack = axp->vr = axp->vs = 0;
  225.             lapbstate(axp,CONNECTED); /* Purge queues */
  226.             break;
  227.         case DISC:
  228.             free_q(&axp->txq);
  229.             sendctl(axp,RESPONSE,UA|pf);
  230.             stop_timer(&axp->t1);
  231.             stop_timer(&axp->t3);
  232.             axp->response = UA;
  233.             lapbstate(axp,DISCONNECTED);
  234.             break;
  235. /* This code is cribbed from the NOS version, in order to make a */
  236. /* temporary fix to a pathological looping behavior during connect (dmf) */
  237.         case DM:
  238.             lapbstate(axp,DISCONNECTED);
  239.             break;
  240.         case UA:
  241.             est_link(axp);
  242.             lapbstate(axp,SETUP);    /* Re-establish */    
  243.             break;
  244. /* End of cribbed code (dmf) */            
  245.         case FRMR:
  246.             est_link(axp);
  247.             lapbstate(axp,SETUP);    /* Re-establish link */
  248.             break;
  249.         case RR:
  250.         case RNR:
  251.             axp->remotebusy = (control == RNR) ? YES : NO;
  252.             if(axp->proto == V1 || final){
  253.                 stop_timer(&axp->t1);
  254.                 (void)ackours(axp,nr);
  255.                 if(axp->unack != 0){
  256.                     inv_rex(axp);
  257.                 } else {
  258.                     start_timer(&axp->t3);
  259.                     lapbstate(axp,CONNECTED);
  260.                 }
  261.             } else {
  262.                 if(poll)
  263.                     enq_resp(axp);
  264.                 (void)ackours(axp,nr);
  265.                 /* Keep timer running even if all frames
  266.                  * were acked, since we must see a Final
  267.                  */
  268.                 if(!run_timer(&axp->t1))
  269.                     start_timer(&axp->t1);
  270.             }
  271.             break;
  272.         case REJ:
  273.             axp->remotebusy = NO;
  274.             /* Don't insist on a Final response from the old proto */
  275.             if(axp->proto == V1 || final){
  276.                 stop_timer(&axp->t1);
  277.                 (void)ackours(axp,nr);
  278.                 if(axp->unack != 0){
  279.                     inv_rex(axp);
  280.                 } else {
  281.                     start_timer(&axp->t3);
  282.                     lapbstate(axp,CONNECTED);
  283.                 }
  284.             } else {
  285.                 if(poll)
  286.                     enq_resp(axp);
  287.                 (void)ackours(axp,nr);
  288.                 if(axp->unack != 0){
  289.                     /* This is certain to trigger output */
  290.                     inv_rex(axp);
  291.                 }
  292.                 /* A REJ that acks everything but doesn't
  293.                  * have the F bit set can cause a deadlock.
  294.                  * So make sure the timer is running.
  295.                  */
  296.                 if(!run_timer(&axp->t1))
  297.                     start_timer(&axp->t1);
  298.             }
  299.             break;
  300.         case I:
  301.             (void)ackours(axp,nr); /** == -1) */
  302.             /* Make sure timer is running, since an I frame
  303.              * cannot satisfy a poll
  304.              */
  305.             if(!run_timer(&axp->t1))
  306.                 start_timer(&axp->t1);
  307.             if(len_mbuf(axp->rxq) >= axp->window){
  308.                 /* Too bad he didn't listen to us; he'll
  309.                  * have to resend the frame later. This
  310.                  * drastic action is necessary to avoid
  311.                  * memory deadlock.
  312.                  */
  313.                 sendctl(axp,RESPONSE,RNR | pf);
  314.                 free_p(bp);
  315.                 bp = NULLBUF;
  316.                 break;
  317.             }
  318.             /* Reject or ignore I-frames with receive sequence number errors */
  319.             if(ns != axp->vr){
  320.                 if(axp->proto == V1 || !axp->rejsent){
  321.                     axp->rejsent = YES;
  322.                     sendctl(axp,RESPONSE,REJ | pf);
  323.                 }
  324.                 axp->response = 0;
  325.                 stop_timer(&axp->t2);
  326.                 break;
  327.             }
  328.             axp->rejsent = NO;
  329.             axp->vr = (axp->vr+1) & MMASK;
  330.             tmp = len_mbuf(axp->rxq) >= axp->window ? RNR : RR;
  331.             if(poll){
  332.                 sendctl(axp,RESPONSE,tmp|PF);
  333.             } else {
  334.                 axp->response = tmp;
  335.                 start_timer(&axp->t2);
  336.             }
  337.             procdata(axp,bp);
  338.             bp = NULLBUF;
  339.             break;
  340.         default:
  341.             break;        /* Ignored */